package org.third.common.utils;

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

public class HttpClientUtils {
	
	@SuppressWarnings("deprecation")
	public static CloseableHttpClient getCertificateIngnoredHttpClient(){
		CloseableHttpClient httpClient = null;
		try {
			httpClient = HttpClients.custom().
			setHostnameVerifier(new AllowAllHostnameVerifier()).
			setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy()
			{
			    public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
			    {
			        return true;
			    }
			}).build()).build();
		} catch (Exception e) {
			throw new RuntimeException("Can't build SSL ingored httpclient");
		}
		return httpClient;
	}
	
	public static CloseableHttpClient getCertificateIngnoredAndWithClientCertificateHttpClient(String cerPath, String cerPwd){
		return getCertificateIngnoredAndWithClientCertificateHttpWithPool(cerPath, cerPwd, null);
	}
	
	public static CloseableHttpClient getCertificateIngnoredAndWithClientCertificateHttpClient(String cerPath, String cerPwd, Integer pool){
		return getCertificateIngnoredAndWithClientCertificateHttpWithPool(cerPath, cerPwd, pool);
	}
	
	private static CloseableHttpClient getCertificateIngnoredAndWithClientCertificateHttpWithPool(String cerPath, String cerPwd, Integer pool){
		CloseableHttpClient httpclient = null;
		try{
			TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
				public java.security.cert.X509Certificate[] getAcceptedIssuers() {
					return null;
				}
			
				public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
				}
			
				public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
				}
			} };
			
			SSLContext sslcontext = SSLContext.getInstance("TLS");
			sslcontext.init(getKeyManager(cerPath, cerPwd), trustAllCerts, new java.security.SecureRandom());
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,
					new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" }, null, new HostnameVerifier() {
						@Override
						public boolean verify(String arg0, SSLSession arg1) {
							return true;
						}
					});
			if(pool == null || pool <= 0){
				httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
			}else{
				//http://stackoverflow.com/questions/19517538/ignoring-ssl-certificate-in-apache-httpclient-4-3
				Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
						.<ConnectionSocketFactory> create().register("https", sslsf)
				        .build();
				PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
				connManager.setMaxTotal(pool);
				connManager.setDefaultMaxPerRoute(pool);
				httpclient = HttpClients.custom().setConnectionManager(connManager).build();
			}
		}catch(Exception e){
			throw new RuntimeException("Faild to create httpclient for Etcd client", e);
		}
		return httpclient;
	}
	
	
	private static KeyManager[] getKeyManager(String cerPath, String cerPwd) throws Exception {
		KeyManager[] keyManager = null;
		FileInputStream fip=null;
		try{	
			KeyStore ks = KeyStore.getInstance("PKCS12");
//			ks.load(new FileInputStream("C:\\Program Files (x86)\\Java\\jre1.8.0_111\\client.p12"), cerPwd.toCharArray());
			fip = new FileInputStream(cerPath);
			ks.load(fip, cerPwd.toCharArray());
			KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
			kmf.init(ks, cerPwd.toCharArray());
			keyManager = kmf.getKeyManagers();
		}catch(Exception e){
			throw new RuntimeException("failed to load client certificate: " + cerPath, e);
		}finally{
			if(fip != null){
				fip.close();
			}
		}
		return keyManager;
	}
}
